package run.halo.app.service;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
import run.halo.app.model.dto.TagWithSiteCountDTO;
import run.halo.app.model.entity.Site;
import run.halo.app.model.entity.SiteTag;
import run.halo.app.model.entity.Tag;
import run.halo.app.model.enums.SiteStatus;
import run.halo.app.service.base.CrudService;

/**
 * Site tag service interface.
 *
 * @author johnniang
 * @author ryanwang
 * @date 2019-03-19
 */
public interface SiteTagService extends CrudService<SiteTag, Integer> {

    /**
     * Lists tags by site id.
     *
     * @param siteId site id must not be null
     * @return a list of tag
     */
    @NonNull
    List<Tag> listTagsBy(@NonNull Integer siteId);

    /**
     * List tag with site count output dtos.
     *
     * @param sort sort info
     * @return a list of tag with site count output dto
     */
    @NonNull
    List<TagWithSiteCountDTO> listTagWithCountDtos(@NonNull Sort sort);

    /**
     * Lists tags list map by site id.
     *
     * @param siteIds site id collection
     * @return tag map (key: siteId, value: a list of tags)
     */
    @NonNull
    Map<Integer, List<Tag>> listTagListMapBy(@Nullable Collection<Integer> siteIds);

    /**
     * Lists sites by tag id.
     *
     * @param tagId tag id must not be null
     * @return a list of site
     */
    @NonNull
    List<Site> listSitesBy(@NonNull Integer tagId);

    /**
     * Lists sites by tag id and site status.
     *
     * @param tagId tag id must not be null
     * @param status site status
     * @return a list of site
     */
    @NonNull
    List<Site> listSitesBy(@NonNull Integer tagId, @NonNull SiteStatus status);

    /**
     * Lists sites by tag slug and site status.
     *
     * @param slug tag slug must not be null
     * @param status site status
     * @return a list of site
     */
    @NonNull
    List<Site> listSitesBy(@NonNull String slug, @NonNull SiteStatus status);

    /**
     * Pages sites by tag id.
     *
     * @param tagId must not be null
     * @param pageable must not be null
     * @return a page of site
     */
    Page<Site> pageSitesBy(@NonNull Integer tagId, Pageable pageable);

    /**
     * Pages sites by tag id and site status.
     *
     * @param tagId must not be null
     * @param status site status
     * @param pageable must not be null
     * @return a page of site
     */
    Page<Site> pageSitesBy(@NonNull Integer tagId, @NonNull SiteStatus status, Pageable pageable);

    /**
     * Merges or creates site tags by site id and tag id set if absent.
     *
     * @param siteId site id must not be null
     * @param tagIds tag id set
     * @return a list of site tag
     */
    @NonNull
    List<SiteTag> mergeOrCreateByIfAbsent(@NonNull Integer siteId, @Nullable Set<Integer> tagIds);

    /**
     * Lists site tags by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site tag
     */
    @NonNull
    List<SiteTag> listBySiteId(@NonNull Integer siteId);

    /**
     * Lists site tags by tag id.
     *
     * @param tagId tag id must not be null
     * @return a list of site tag
     */
    @NonNull
    List<SiteTag> listByTagId(@NonNull Integer tagId);

    /**
     * Lists tag id set by site id.
     *
     * @param siteId site id must not be null
     * @return a set of tag id
     */
    @NonNull
    Set<Integer> listTagIdsBySiteId(@NonNull Integer siteId);

    /**
     * Removes site tags by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site tag
     */
    @NonNull
    @Transactional
    List<SiteTag> removeBySiteId(@NonNull Integer siteId);

    /**
     * Removes site tags by tag id.
     *
     * @param tagId tag id must not be null
     * @return a list of site tag
     */
    @NonNull
    @Transactional(rollbackFor = Exception.class)
    List<SiteTag> removeByTagId(@NonNull Integer tagId);
}
